package roaring
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"strconv"
"github.com/RoaringBitmap/roaring/internal"
"github.com/bits-and-blooms/bitset"
)
type Bitmap struct {
highlowcontainer roaringArray
}
func (rb *Bitmap ) ToBase64 () (string , error ) {
buf := new (bytes .Buffer )
_ , err := rb .WriteTo (buf )
return base64 .StdEncoding .EncodeToString (buf .Bytes ()), err
}
func (rb *Bitmap ) FromBase64 (str string ) (int64 , error ) {
data , err := base64 .StdEncoding .DecodeString (str )
if err != nil {
return 0 , err
}
buf := bytes .NewBuffer (data )
return rb .ReadFrom (buf )
}
func (rb *Bitmap ) WriteTo (stream io .Writer ) (int64 , error ) {
return rb .highlowcontainer .writeTo (stream )
}
func (rb *Bitmap ) ToBytes () ([]byte , error ) {
return rb .highlowcontainer .toBytes ()
}
const wordSize = uint64 (64 )
const log2WordSize = uint64 (6 )
const capacity = ^uint64 (0 )
const bitmapContainerSize = (1 << 16 ) / 64
func (rb *Bitmap ) DenseSize () uint64 {
if rb .highlowcontainer .size () == 0 {
return 0
}
maximum := 1 + uint64 (rb .Maximum ())
if maximum > (capacity - wordSize + 1 ) {
return uint64 (capacity >> log2WordSize )
}
return uint64 ((maximum + (wordSize - 1 )) >> log2WordSize )
}
func (rb *Bitmap ) ToDense () []uint64 {
sz := rb .DenseSize ()
if sz == 0 {
return nil
}
bitmap := make ([]uint64 , sz )
rb .WriteDenseTo (bitmap )
return bitmap
}
func FromDense (bitmap []uint64 , doCopy bool ) *Bitmap {
sz := (len (bitmap ) + bitmapContainerSize - 1 ) / bitmapContainerSize
rb := &Bitmap {
highlowcontainer : roaringArray {
containers : make ([]container , 0 , sz ),
keys : make ([]uint16 , 0 , sz ),
needCopyOnWrite : make ([]bool , 0 , sz ),
},
}
rb .FromDense (bitmap , doCopy )
return rb
}
func (rb *Bitmap ) FromDense (bitmap []uint64 , doCopy bool ) {
if len (bitmap ) == 0 {
return
}
var k uint16
const size = bitmapContainerSize
for len (bitmap ) > 0 {
hi := size
if len (bitmap ) < size {
hi = len (bitmap )
}
words := bitmap [:hi ]
count := int (popcntSlice (words ))
switch {
case count > arrayDefaultMaxSize :
c := &bitmapContainer {cardinality : count , bitmap : words }
cow := true
if doCopy || len (words ) < size {
c .bitmap = make ([]uint64 , size )
copy (c .bitmap , words )
cow = false
}
rb .highlowcontainer .appendContainer (k , c , cow )
case count > 0 :
c := &arrayContainer {content : make ([]uint16 , count )}
var pos , base int
for _ , w := range words {
for w != 0 {
t := w & -w
c .content [pos ] = uint16 (base + int (popcount (t -1 )))
pos ++
w ^= t
}
base += 64
}
rb .highlowcontainer .appendContainer (k , c , false )
}
bitmap = bitmap [hi :]
k ++
}
}
func (rb *Bitmap ) WriteDenseTo (bitmap []uint64 ) {
for i , ct := range rb .highlowcontainer .containers {
hb := uint32 (rb .highlowcontainer .keys [i ]) << 16
switch c := ct .(type ) {
case *arrayContainer :
for _ , x := range c .content {
n := int (hb | uint32 (x ))
bitmap [n >>log2WordSize ] |= uint64 (1 ) << uint (x %64 )
}
case *bitmapContainer :
copy (bitmap [int (hb )>>log2WordSize :], c .bitmap )
case *runContainer16 :
for j := range c .iv {
start := uint32 (c .iv [j ].start )
end := start + uint32 (c .iv [j ].length ) + 1
lo := int (hb |start ) >> log2WordSize
hi := int (hb |(end -1 )) >> log2WordSize
if lo == hi {
bitmap [lo ] |= (^uint64 (0 ) << uint (start %64 )) &
(^uint64 (0 ) >> (uint (-end ) % 64 ))
continue
}
bitmap [lo ] |= ^uint64 (0 ) << uint (start %64 )
for n := lo + 1 ; n < hi ; n ++ {
bitmap [n ] = ^uint64 (0 )
}
bitmap [hi ] |= ^uint64 (0 ) >> (uint (-end ) % 64 )
}
default :
panic ("unsupported container type" )
}
}
}
func (rb *Bitmap ) Checksum () uint64 {
const (
offset = 14695981039346656037
prime = 1099511628211
)
var bytes []byte
hash := uint64 (offset )
bytes = uint16SliceAsByteSlice (rb .highlowcontainer .keys )
for _ , b := range bytes {
hash ^= uint64 (b )
hash *= prime
}
for _ , c := range rb .highlowcontainer .containers {
hash ^= 0
hash *= prime
switch c := c .(type ) {
case *bitmapContainer :
bytes = uint64SliceAsByteSlice (c .bitmap )
case *arrayContainer :
bytes = uint16SliceAsByteSlice (c .content )
case *runContainer16 :
bytes = interval16SliceAsByteSlice (c .iv )
default :
panic ("invalid container type" )
}
if len (bytes ) == 0 {
panic ("empty containers are not supported" )
}
for _ , b := range bytes {
hash ^= uint64 (b )
hash *= prime
}
}
return hash
}
func (rb *Bitmap ) FromUnsafeBytes (data []byte , cookieHeader ...byte ) (p int64 , err error ) {
stream := internal .NewByteBuffer (data )
return rb .ReadFrom (stream )
}
func (rb *Bitmap ) ReadFrom (reader io .Reader , cookieHeader ...byte ) (p int64 , err error ) {
stream , ok := reader .(internal .ByteInput )
if !ok {
byteInputAdapter := internal .ByteInputAdapterPool .Get ().(*internal .ByteInputAdapter )
byteInputAdapter .Reset (reader )
stream = byteInputAdapter
}
p , err = rb .highlowcontainer .readFrom (stream , cookieHeader ...)
if !ok {
internal .ByteInputAdapterPool .Put (stream .(*internal .ByteInputAdapter ))
}
return
}
func (rb *Bitmap ) FromBuffer (buf []byte ) (p int64 , err error ) {
stream := internal .ByteBufferPool .Get ().(*internal .ByteBuffer )
stream .Reset (buf )
p , err = rb .highlowcontainer .readFrom (stream )
internal .ByteBufferPool .Put (stream )
return
}
func (rb *Bitmap ) RunOptimize () {
rb .highlowcontainer .runOptimize ()
}
func (rb *Bitmap ) HasRunCompression () bool {
return rb .highlowcontainer .hasRunCompression ()
}
func (rb *Bitmap ) MarshalBinary () ([]byte , error ) {
return rb .ToBytes ()
}
func (rb *Bitmap ) UnmarshalBinary (data []byte ) error {
r := bytes .NewReader (data )
_ , err := rb .ReadFrom (r )
return err
}
func NewBitmap () *Bitmap {
return &Bitmap {}
}
func New () *Bitmap {
return &Bitmap {}
}
func (rb *Bitmap ) Clear () {
rb .highlowcontainer .clear ()
}
func (rb *Bitmap ) ToBitSet () *bitset .BitSet {
return bitset .From (rb .ToDense ())
}
func FromBitSet (bitset *bitset .BitSet ) *Bitmap {
return FromDense (bitset .Bytes (), false )
}
func (rb *Bitmap ) ToArray () []uint32 {
array := make ([]uint32 , rb .GetCardinality ())
pos := 0
pos2 := 0
for pos < rb .highlowcontainer .size () {
hs := uint32 (rb .highlowcontainer .getKeyAtIndex (pos )) << 16
c := rb .highlowcontainer .getContainerAtIndex (pos )
pos ++
pos2 = c .fillLeastSignificant16bits (array , pos2 , hs )
}
return array
}
func (rb *Bitmap ) GetSizeInBytes () uint64 {
size := uint64 (8 )
for _ , c := range rb .highlowcontainer .containers {
size += uint64 (2 ) + uint64 (c .getSizeInBytes ())
}
return size
}
func (rb *Bitmap ) GetSerializedSizeInBytes () uint64 {
return rb .highlowcontainer .serializedSizeInBytes ()
}
func BoundSerializedSizeInBytes (cardinality uint64 , universeSize uint64 ) uint64 {
contnbr := (universeSize + uint64 (65535 )) / uint64 (65536 )
if contnbr > cardinality {
contnbr = cardinality
}
headermax := 8 *contnbr + 4
if 4 > (contnbr +7 )/8 {
headermax += 4
} else {
headermax += (contnbr + 7 ) / 8
}
valsarray := uint64 (arrayContainerSizeInBytes (int (cardinality )))
valsbitmap := contnbr * uint64 (bitmapContainerSizeInBytes ())
valsbest := valsarray
if valsbest > valsbitmap {
valsbest = valsbitmap
}
return valsbest + headermax
}
type IntIterable interface {
HasNext () bool
Next () uint32
}
type IntPeekable interface {
IntIterable
PeekNext () uint32
AdvanceIfNeeded (minval uint32 )
}
type intIterator struct {
pos int
hs uint32
iter shortPeekable
highlowcontainer *roaringArray
shortIter shortIterator
runIter runIterator16
bitmapIter bitmapContainerShortIterator
}
func (ii *intIterator ) HasNext () bool {
return ii .pos < ii .highlowcontainer .size ()
}
func (ii *intIterator ) init () {
if ii .highlowcontainer .size () > ii .pos {
ii .hs = uint32 (ii .highlowcontainer .getKeyAtIndex (ii .pos )) << 16
c := ii .highlowcontainer .getContainerAtIndex (ii .pos )
switch t := c .(type ) {
case *arrayContainer :
ii .shortIter = shortIterator {t .content , 0 }
ii .iter = &ii .shortIter
case *runContainer16 :
ii .runIter = runIterator16 {rc : t , curIndex : 0 , curPosInIndex : 0 }
ii .iter = &ii .runIter
case *bitmapContainer :
ii .bitmapIter = bitmapContainerShortIterator {t , t .NextSetBit (0 )}
ii .iter = &ii .bitmapIter
}
}
}
func (ii *intIterator ) Next () uint32 {
x := uint32 (ii .iter .next ()) | ii .hs
if !ii .iter .hasNext () {
ii .pos = ii .pos + 1
ii .init ()
}
return x
}
func (ii *intIterator ) PeekNext () uint32 {
return uint32 (ii .iter .peekNext ()&maxLowBit ) | ii .hs
}
func (ii *intIterator ) AdvanceIfNeeded (minval uint32 ) {
to := minval & 0xffff0000
for ii .HasNext () && ii .hs < to {
ii .pos ++
ii .init ()
}
if ii .HasNext () && ii .hs == to {
ii .iter .advanceIfNeeded (lowbits (minval ))
if !ii .iter .hasNext () {
ii .pos ++
ii .init ()
}
}
}
type IntIterator = intIterator
func (ii *intIterator ) Initialize (a *Bitmap ) {
ii .pos = 0
ii .highlowcontainer = &a .highlowcontainer
ii .init ()
}
type intReverseIterator struct {
pos int
hs uint32
iter shortIterable
highlowcontainer *roaringArray
shortIter reverseIterator
runIter runReverseIterator16
bitmapIter reverseBitmapContainerShortIterator
}
func (ii *intReverseIterator ) HasNext () bool {
return ii .pos >= 0
}
func (ii *intReverseIterator ) init () {
if ii .pos >= 0 {
ii .hs = uint32 (ii .highlowcontainer .getKeyAtIndex (ii .pos )) << 16
c := ii .highlowcontainer .getContainerAtIndex (ii .pos )
switch t := c .(type ) {
case *arrayContainer :
ii .shortIter = reverseIterator {t .content , len (t .content ) - 1 }
ii .iter = &ii .shortIter
case *runContainer16 :
index := int (len (t .iv )) - 1
pos := uint16 (0 )
if index >= 0 {
pos = t .iv [index ].length
}
ii .runIter = runReverseIterator16 {rc : t , curIndex : index , curPosInIndex : pos }
ii .iter = &ii .runIter
case *bitmapContainer :
pos := -1
if t .cardinality > 0 {
pos = int (t .maximum ())
}
ii .bitmapIter = reverseBitmapContainerShortIterator {t , pos }
ii .iter = &ii .bitmapIter
}
} else {
ii .iter = nil
}
}
func (ii *intReverseIterator ) Next () uint32 {
x := uint32 (ii .iter .next ()) | ii .hs
if !ii .iter .hasNext () {
ii .pos = ii .pos - 1
ii .init ()
}
return x
}
type IntReverseIterator = intReverseIterator
func (ii *intReverseIterator ) Initialize (a *Bitmap ) {
ii .highlowcontainer = &a .highlowcontainer
ii .pos = a .highlowcontainer .size () - 1
ii .init ()
}
type ManyIntIterable interface {
NextMany (buf []uint32 ) int
NextMany64 (hs uint64 , buf []uint64 ) int
}
type manyIntIterator struct {
pos int
hs uint32
iter manyIterable
highlowcontainer *roaringArray
shortIter shortIterator
runIter runIterator16
bitmapIter bitmapContainerManyIterator
}
func (ii *manyIntIterator ) init () {
if ii .highlowcontainer .size () > ii .pos {
ii .hs = uint32 (ii .highlowcontainer .getKeyAtIndex (ii .pos )) << 16
c := ii .highlowcontainer .getContainerAtIndex (ii .pos )
switch t := c .(type ) {
case *arrayContainer :
ii .shortIter = shortIterator {t .content , 0 }
ii .iter = &ii .shortIter
case *runContainer16 :
ii .runIter = runIterator16 {rc : t , curIndex : 0 , curPosInIndex : 0 }
ii .iter = &ii .runIter
case *bitmapContainer :
ii .bitmapIter = bitmapContainerManyIterator {t , -1 , 0 }
ii .iter = &ii .bitmapIter
}
} else {
ii .iter = nil
}
}
func (ii *manyIntIterator ) NextMany (buf []uint32 ) int {
n := 0
for n < len (buf ) {
if ii .iter == nil {
break
}
moreN := ii .iter .nextMany (ii .hs , buf [n :])
n += moreN
if moreN == 0 {
ii .pos = ii .pos + 1
ii .init ()
}
}
return n
}
func (ii *manyIntIterator ) NextMany64 (hs64 uint64 , buf []uint64 ) int {
n := 0
for n < len (buf ) {
if ii .iter == nil {
break
}
hs := uint64 (ii .hs ) | hs64
moreN := ii .iter .nextMany64 (hs , buf [n :])
n += moreN
if moreN == 0 {
ii .pos = ii .pos + 1
ii .init ()
}
}
return n
}
type ManyIntIterator = manyIntIterator
func (ii *manyIntIterator ) Initialize (a *Bitmap ) {
ii .pos = 0
ii .highlowcontainer = &a .highlowcontainer
ii .init ()
}
func (rb *Bitmap ) String () string {
var buffer bytes .Buffer
start := []byte ("{" )
buffer .Write (start )
i := rb .Iterator ()
counter := 0
if i .HasNext () {
counter = counter + 1
buffer .WriteString (strconv .FormatInt (int64 (i .Next ()), 10 ))
}
for i .HasNext () {
buffer .WriteString ("," )
counter = counter + 1
if counter > 0x40000 {
buffer .WriteString ("..." )
break
}
buffer .WriteString (strconv .FormatInt (int64 (i .Next ()), 10 ))
}
buffer .WriteString ("}" )
return buffer .String ()
}
func (rb *Bitmap ) Iterate (cb func (x uint32 ) bool ) {
for i := 0 ; i < rb .highlowcontainer .size (); i ++ {
hs := uint32 (rb .highlowcontainer .getKeyAtIndex (i )) << 16
c := rb .highlowcontainer .getContainerAtIndex (i )
var shouldContinue bool
switch t := c .(type ) {
case *arrayContainer :
shouldContinue = t .iterate (func (x uint16 ) bool {
return cb (uint32 (x ) | hs )
})
case *runContainer16 :
shouldContinue = t .iterate (func (x uint16 ) bool {
return cb (uint32 (x ) | hs )
})
case *bitmapContainer :
shouldContinue = t .iterate (func (x uint16 ) bool {
return cb (uint32 (x ) | hs )
})
}
if !shouldContinue {
break
}
}
}
func (rb *Bitmap ) Iterator () IntPeekable {
p := new (intIterator )
p .Initialize (rb )
return p
}
func (rb *Bitmap ) ReverseIterator () IntIterable {
p := new (intReverseIterator )
p .Initialize (rb )
return p
}
func (rb *Bitmap ) ManyIterator () ManyIntIterable {
p := new (manyIntIterator )
p .Initialize (rb )
return p
}
func (rb *Bitmap ) Clone () *Bitmap {
ptr := new (Bitmap )
ptr .highlowcontainer = *rb .highlowcontainer .clone ()
return ptr
}
func (rb *Bitmap ) Minimum () uint32 {
if len (rb .highlowcontainer .containers ) == 0 {
panic ("Empty bitmap" )
}
return uint32 (rb .highlowcontainer .containers [0 ].minimum ()) | (uint32 (rb .highlowcontainer .keys [0 ]) << 16 )
}
func (rb *Bitmap ) Maximum () uint32 {
if len (rb .highlowcontainer .containers ) == 0 {
panic ("Empty bitmap" )
}
lastindex := len (rb .highlowcontainer .containers ) - 1
return uint32 (rb .highlowcontainer .containers [lastindex ].maximum ()) | (uint32 (rb .highlowcontainer .keys [lastindex ]) << 16 )
}
func (rb *Bitmap ) Contains (x uint32 ) bool {
hb := highbits (x )
c := rb .highlowcontainer .getContainer (hb )
return c != nil && c .contains (lowbits (x ))
}
func (rb *Bitmap ) ContainsInt (x int ) bool {
return rb .Contains (uint32 (x ))
}
func (rb *Bitmap ) Equals (o interface {}) bool {
srb , ok := o .(*Bitmap )
if ok {
return srb .highlowcontainer .equals (rb .highlowcontainer )
}
return false
}
func AddOffset (x *Bitmap , offset uint32 ) (answer *Bitmap ) {
return AddOffset64 (x , int64 (offset ))
}
func AddOffset64 (x *Bitmap , offset int64 ) (answer *Bitmap ) {
var containerOffset64 int64
if offset < 0 {
containerOffset64 = (offset - (1 << 16 ) + 1 ) / (1 << 16 )
} else {
containerOffset64 = offset >> 16
}
answer = New ()
if containerOffset64 >= (1 <<16 ) || containerOffset64 < -(1 <<16 ) {
return answer
}
containerOffset := int32 (containerOffset64 )
inOffset := (uint16 )(offset - containerOffset64 *(1 <<16 ))
if inOffset == 0 {
for pos := 0 ; pos < x .highlowcontainer .size (); pos ++ {
key := int32 (x .highlowcontainer .getKeyAtIndex (pos ))
key += containerOffset
if key >= 0 && key <= MaxUint16 {
c := x .highlowcontainer .getContainerAtIndex (pos ).clone ()
answer .highlowcontainer .appendContainer (uint16 (key ), c , false )
}
}
} else {
for pos := 0 ; pos < x .highlowcontainer .size (); pos ++ {
key := int32 (x .highlowcontainer .getKeyAtIndex (pos ))
key += containerOffset
if key +1 < 0 || key > MaxUint16 {
continue
}
c := x .highlowcontainer .getContainerAtIndex (pos )
lo , hi := c .addOffset (inOffset )
if lo != nil && key >= 0 {
curSize := answer .highlowcontainer .size ()
lastkey := int32 (0 )
if curSize > 0 {
lastkey = int32 (answer .highlowcontainer .getKeyAtIndex (curSize - 1 ))
}
if curSize > 0 && lastkey == key {
prev := answer .highlowcontainer .getContainerAtIndex (curSize - 1 )
orresult := prev .ior (lo )
answer .highlowcontainer .setContainerAtIndex (curSize -1 , orresult )
} else {
answer .highlowcontainer .appendContainer (uint16 (key ), lo , false )
}
}
if hi != nil && key +1 <= MaxUint16 {
answer .highlowcontainer .appendContainer (uint16 (key +1 ), hi , false )
}
}
}
return answer
}
func (rb *Bitmap ) Add (x uint32 ) {
hb := highbits (x )
ra := &rb .highlowcontainer
i := ra .getIndex (hb )
if i >= 0 {
var c container
c = ra .getWritableContainerAtIndex (i ).iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
newac := newArrayContainer ()
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , hb , newac .iaddReturnMinimized (lowbits (x )))
}
}
func (rb *Bitmap ) addwithptr (x uint32 ) (int , container ) {
hb := highbits (x )
ra := &rb .highlowcontainer
i := ra .getIndex (hb )
var c container
if i >= 0 {
c = ra .getWritableContainerAtIndex (i ).iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , c )
return i , c
}
newac := newArrayContainer ()
c = newac .iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , hb , c )
return -i - 1 , c
}
func (rb *Bitmap ) CheckedAdd (x uint32 ) bool {
hb := highbits (x )
i := rb .highlowcontainer .getIndex (hb )
if i >= 0 {
C := rb .highlowcontainer .getWritableContainerAtIndex (i )
oldcard := C .getCardinality ()
C = C .iaddReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , C )
return C .getCardinality () > oldcard
}
newac := newArrayContainer ()
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , hb , newac .iaddReturnMinimized (lowbits (x )))
return true
}
func (rb *Bitmap ) AddInt (x int ) {
rb .Add (uint32 (x ))
}
func (rb *Bitmap ) Remove (x uint32 ) {
hb := highbits (x )
i := rb .highlowcontainer .getIndex (hb )
if i >= 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).iremoveReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , c )
if rb .highlowcontainer .getContainerAtIndex (i ).isEmpty () {
rb .highlowcontainer .removeAtIndex (i )
}
}
}
func (rb *Bitmap ) CheckedRemove (x uint32 ) bool {
hb := highbits (x )
i := rb .highlowcontainer .getIndex (hb )
if i >= 0 {
C := rb .highlowcontainer .getWritableContainerAtIndex (i )
oldcard := C .getCardinality ()
C = C .iremoveReturnMinimized (lowbits (x ))
rb .highlowcontainer .setContainerAtIndex (i , C )
if rb .highlowcontainer .getContainerAtIndex (i ).isEmpty () {
rb .highlowcontainer .removeAtIndex (i )
return true
}
return C .getCardinality () < oldcard
}
return false
}
func (rb *Bitmap ) IsEmpty () bool {
return rb .highlowcontainer .size () == 0
}
func (rb *Bitmap ) GetCardinality () uint64 {
size := uint64 (0 )
for _ , c := range rb .highlowcontainer .containers {
size += uint64 (c .getCardinality ())
}
return size
}
func (rb *Bitmap ) Rank (x uint32 ) uint64 {
size := uint64 (0 )
for i := 0 ; i < rb .highlowcontainer .size (); i ++ {
key := rb .highlowcontainer .getKeyAtIndex (i )
if key > highbits (x ) {
return size
}
if key < highbits (x ) {
size += uint64 (rb .highlowcontainer .getContainerAtIndex (i ).getCardinality ())
} else {
return size + uint64 (rb .highlowcontainer .getContainerAtIndex (i ).rank (lowbits (x )))
}
}
return size
}
func (rb *Bitmap ) Select (x uint32 ) (uint32 , error ) {
remaining := x
for i := 0 ; i < rb .highlowcontainer .size (); i ++ {
c := rb .highlowcontainer .getContainerAtIndex (i )
card := uint32 (c .getCardinality ())
if remaining >= card {
remaining -= card
} else {
key := rb .highlowcontainer .getKeyAtIndex (i )
return uint32 (key )<<16 + uint32 (c .selectInt (uint16 (remaining ))), nil
}
}
return 0 , fmt .Errorf ("cannot find %dth integer in a bitmap with only %d items" , x , rb .GetCardinality ())
}
func (rb *Bitmap ) And (x2 *Bitmap ) {
pos1 := 0
pos2 := 0
intersectionsize := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getWritableContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
diff := c1 .iand (c2 )
if !diff .isEmpty () {
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , diff , false )
intersectionsize ++
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
rb .highlowcontainer .resize (intersectionsize )
}
func (rb *Bitmap ) OrCardinality (x2 *Bitmap ) uint64 {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
answer := uint64 (0 )
main :
for {
if (pos1 < length1 ) && (pos2 < length2 ) {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
answer += uint64 (rb .highlowcontainer .getContainerAtIndex (pos1 ).getCardinality ())
pos1 ++
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 > s2 {
answer += uint64 (x2 .highlowcontainer .getContainerAtIndex (pos2 ).getCardinality ())
pos2 ++
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
answer += uint64 (rb .highlowcontainer .getContainerAtIndex (pos1 ).or (x2 .highlowcontainer .getContainerAtIndex (pos2 )).getCardinality ())
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
for ; pos1 < length1 ; pos1 ++ {
answer += uint64 (rb .highlowcontainer .getContainerAtIndex (pos1 ).getCardinality ())
}
for ; pos2 < length2 ; pos2 ++ {
answer += uint64 (x2 .highlowcontainer .getContainerAtIndex (pos2 ).getCardinality ())
}
return answer
}
func (rb *Bitmap ) AndCardinality (x2 *Bitmap ) uint64 {
pos1 := 0
pos2 := 0
answer := uint64 (0 )
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
answer += uint64 (c1 .andCardinality (c2 ))
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
return answer
}
func (rb *Bitmap ) IntersectsWithInterval (x , y uint64 ) bool {
if x >= y {
return false
}
if x > MaxUint32 {
return false
}
it := intIterator {}
it .Initialize (rb )
it .AdvanceIfNeeded (uint32 (x ))
if !it .HasNext () {
return false
}
if uint64 (it .Next ()) >= y {
return false
}
return true
}
func (rb *Bitmap ) Intersects (x2 *Bitmap ) bool {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
if c1 .intersects (c2 ) {
return true
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
return false
}
func (rb *Bitmap ) Xor (x2 *Bitmap ) {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
for {
if (pos1 < length1 ) && (pos2 < length2 ) {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
if s1 < s2 {
pos1 = rb .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break
}
} else if s1 > s2 {
c := x2 .highlowcontainer .getWritableContainerAtIndex (pos2 )
rb .highlowcontainer .insertNewKeyValueAt (pos1 , x2 .highlowcontainer .getKeyAtIndex (pos2 ), c )
length1 ++
pos1 ++
pos2 ++
} else {
c := rb .highlowcontainer .getContainerAtIndex (pos1 ).xor (x2 .highlowcontainer .getContainerAtIndex (pos2 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (pos1 , c )
pos1 ++
} else {
rb .highlowcontainer .removeAtIndex (pos1 )
length1 --
}
pos2 ++
}
} else {
break
}
}
if pos1 == length1 {
rb .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
}
}
func (rb *Bitmap ) Or (x2 *Bitmap ) {
pos1 := 0
pos2 := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for (pos1 < length1 ) && (pos2 < length2 ) {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
pos1 ++
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 > s2 {
rb .highlowcontainer .insertNewKeyValueAt (pos1 , s2 , x2 .highlowcontainer .getContainerAtIndex (pos2 ).clone ())
pos1 ++
length1 ++
pos2 ++
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
rb .highlowcontainer .replaceKeyAndContainerAtIndex (pos1 , s1 , rb .highlowcontainer .getUnionedWritableContainer (pos1 , x2 .highlowcontainer .getContainerAtIndex (pos2 )), false )
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
}
if pos1 == length1 {
rb .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
}
}
func (rb *Bitmap ) AndNot (x2 *Bitmap ) {
pos1 := 0
pos2 := 0
intersectionsize := 0
length1 := rb .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
c1 := rb .highlowcontainer .getWritableContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
diff := c1 .iandNot (c2 )
if !diff .isEmpty () {
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , diff , false )
intersectionsize ++
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
mustCopyOnWrite := rb .highlowcontainer .needsCopyOnWrite (pos1 )
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , c1 , mustCopyOnWrite )
intersectionsize ++
pos1 ++
if pos1 == length1 {
break main
}
s1 = rb .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
for pos1 < length1 {
c1 := rb .highlowcontainer .getContainerAtIndex (pos1 )
s1 := rb .highlowcontainer .getKeyAtIndex (pos1 )
mustCopyOnWrite := rb .highlowcontainer .needsCopyOnWrite (pos1 )
rb .highlowcontainer .replaceKeyAndContainerAtIndex (intersectionsize , s1 , c1 , mustCopyOnWrite )
intersectionsize ++
pos1 ++
}
rb .highlowcontainer .resize (intersectionsize )
}
func Or (x1 , x2 *Bitmap ) *Bitmap {
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for (pos1 < length1 ) && (pos2 < length2 ) {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
answer .highlowcontainer .appendCopy (x1 .highlowcontainer , pos1 )
pos1 ++
if pos1 == length1 {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 > s2 {
answer .highlowcontainer .appendCopy (x2 .highlowcontainer , pos2 )
pos2 ++
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
answer .highlowcontainer .appendContainer (s1 , x1 .highlowcontainer .getContainerAtIndex (pos1 ).or (x2 .highlowcontainer .getContainerAtIndex (pos2 )), false )
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
}
if pos1 == length1 {
answer .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
} else if pos2 == length2 {
answer .highlowcontainer .appendCopyMany (x1 .highlowcontainer , pos1 , length1 )
}
return answer
}
func And (x1 , x2 *Bitmap ) *Bitmap {
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for pos1 < length1 && pos2 < length2 {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 == s2 {
C := x1 .highlowcontainer .getContainerAtIndex (pos1 )
C = C .and (x2 .highlowcontainer .getContainerAtIndex (pos2 ))
if !C .isEmpty () {
answer .highlowcontainer .appendContainer (s1 , C , false )
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else if s1 < s2 {
pos1 = x1 .highlowcontainer .advanceUntil (s2 , pos1 )
if pos1 == length1 {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
}
return answer
}
func Xor (x1 , x2 *Bitmap ) *Bitmap {
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
for {
if (pos1 < length1 ) && (pos2 < length2 ) {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
if s1 < s2 {
answer .highlowcontainer .appendCopy (x1 .highlowcontainer , pos1 )
pos1 ++
} else if s1 > s2 {
answer .highlowcontainer .appendCopy (x2 .highlowcontainer , pos2 )
pos2 ++
} else {
c := x1 .highlowcontainer .getContainerAtIndex (pos1 ).xor (x2 .highlowcontainer .getContainerAtIndex (pos2 ))
if !c .isEmpty () {
answer .highlowcontainer .appendContainer (s1 , c , false )
}
pos1 ++
pos2 ++
}
} else {
break
}
}
if pos1 == length1 {
answer .highlowcontainer .appendCopyMany (x2 .highlowcontainer , pos2 , length2 )
} else if pos2 == length2 {
answer .highlowcontainer .appendCopyMany (x1 .highlowcontainer , pos1 , length1 )
}
return answer
}
func AndNot (x1 , x2 *Bitmap ) *Bitmap {
answer := NewBitmap ()
pos1 := 0
pos2 := 0
length1 := x1 .highlowcontainer .size ()
length2 := x2 .highlowcontainer .size ()
main :
for {
if pos1 < length1 && pos2 < length2 {
s1 := x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 := x2 .highlowcontainer .getKeyAtIndex (pos2 )
for {
if s1 < s2 {
answer .highlowcontainer .appendCopy (x1 .highlowcontainer , pos1 )
pos1 ++
if pos1 == length1 {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
} else if s1 == s2 {
c1 := x1 .highlowcontainer .getContainerAtIndex (pos1 )
c2 := x2 .highlowcontainer .getContainerAtIndex (pos2 )
diff := c1 .andNot (c2 )
if !diff .isEmpty () {
answer .highlowcontainer .appendContainer (s1 , diff , false )
}
pos1 ++
pos2 ++
if (pos1 == length1 ) || (pos2 == length2 ) {
break main
}
s1 = x1 .highlowcontainer .getKeyAtIndex (pos1 )
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
} else {
pos2 = x2 .highlowcontainer .advanceUntil (s1 , pos2 )
if pos2 == length2 {
break main
}
s2 = x2 .highlowcontainer .getKeyAtIndex (pos2 )
}
}
} else {
break
}
}
if pos2 == length2 {
answer .highlowcontainer .appendCopyMany (x1 .highlowcontainer , pos1 , length1 )
}
return answer
}
func (rb *Bitmap ) AddMany (dat []uint32 ) {
if len (dat ) == 0 {
return
}
prev := dat [0 ]
idx , c := rb .addwithptr (prev )
for _ , i := range dat [1 :] {
if highbits (prev ) == highbits (i ) {
c = c .iaddReturnMinimized (lowbits (i ))
rb .highlowcontainer .setContainerAtIndex (idx , c )
} else {
idx , c = rb .addwithptr (i )
}
prev = i
}
}
func BitmapOf (dat ...uint32 ) *Bitmap {
ans := NewBitmap ()
ans .AddMany (dat )
return ans
}
func (rb *Bitmap ) Flip (rangeStart , rangeEnd uint64 ) {
if rangeEnd > MaxUint32 +1 {
panic ("rangeEnd > MaxUint32+1" )
}
if rangeStart > MaxUint32 +1 {
panic ("rangeStart > MaxUint32+1" )
}
if rangeStart >= rangeEnd {
return
}
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
var max uint32 = maxLowBit
for hb := hbStart ; hb <= hbLast ; hb ++ {
var containerStart uint32
if hb == hbStart {
containerStart = uint32 (lbStart )
}
containerLast := max
if hb == hbLast {
containerLast = uint32 (lbLast )
}
i := rb .highlowcontainer .getIndex (uint16 (hb ))
if i >= 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).inot (int (containerStart ), int (containerLast )+1 )
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
rb .highlowcontainer .removeAtIndex (i )
}
} else {
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , uint16 (hb ), rangeOfOnes (int (containerStart ), int (containerLast )))
}
}
}
func (rb *Bitmap ) FlipInt (rangeStart , rangeEnd int ) {
rb .Flip (uint64 (rangeStart ), uint64 (rangeEnd ))
}
func (rb *Bitmap ) AddRange (rangeStart , rangeEnd uint64 ) {
if rangeStart >= rangeEnd {
return
}
if rangeEnd -1 > MaxUint32 {
panic ("rangeEnd-1 > MaxUint32" )
}
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
var max uint32 = maxLowBit
for hb := hbStart ; hb <= hbLast ; hb ++ {
containerStart := uint32 (0 )
if hb == hbStart {
containerStart = lbStart
}
containerLast := max
if hb == hbLast {
containerLast = lbLast
}
i := rb .highlowcontainer .getIndex (uint16 (hb ))
if i >= 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).iaddRange (int (containerStart ), int (containerLast )+1 )
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
rb .highlowcontainer .insertNewKeyValueAt (-i -1 , uint16 (hb ), rangeOfOnes (int (containerStart ), int (containerLast )))
}
}
}
func (rb *Bitmap ) RemoveRange (rangeStart , rangeEnd uint64 ) {
if rangeStart >= rangeEnd {
return
}
if rangeEnd -1 > MaxUint32 {
rangeEnd = uint64 (0x100000000 )
}
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
var max uint32 = maxLowBit
if hbStart == hbLast {
i := rb .highlowcontainer .getIndex (uint16 (hbStart ))
if i < 0 {
return
}
c := rb .highlowcontainer .getWritableContainerAtIndex (i ).iremoveRange (int (lbStart ), int (lbLast +1 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (i , c )
} else {
rb .highlowcontainer .removeAtIndex (i )
}
return
}
ifirst := rb .highlowcontainer .getIndex (uint16 (hbStart ))
ilast := rb .highlowcontainer .getIndex (uint16 (hbLast ))
if ifirst >= 0 {
if lbStart != 0 {
c := rb .highlowcontainer .getWritableContainerAtIndex (ifirst ).iremoveRange (int (lbStart ), int (max +1 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (ifirst , c )
ifirst ++
}
}
} else {
ifirst = -ifirst - 1
}
if ilast >= 0 {
if lbLast != max {
c := rb .highlowcontainer .getWritableContainerAtIndex (ilast ).iremoveRange (int (0 ), int (lbLast +1 ))
if !c .isEmpty () {
rb .highlowcontainer .setContainerAtIndex (ilast , c )
} else {
ilast ++
}
} else {
ilast ++
}
} else {
ilast = -ilast - 1
}
rb .highlowcontainer .removeIndexRange (ifirst , ilast )
}
func Flip (bm *Bitmap , rangeStart , rangeEnd uint64 ) *Bitmap {
if rangeStart >= rangeEnd {
return bm .Clone ()
}
if rangeStart > MaxUint32 {
panic ("rangeStart > MaxUint32" )
}
if rangeEnd -1 > MaxUint32 {
panic ("rangeEnd-1 > MaxUint32" )
}
answer := NewBitmap ()
hbStart := uint32 (highbits (uint32 (rangeStart )))
lbStart := uint32 (lowbits (uint32 (rangeStart )))
hbLast := uint32 (highbits (uint32 (rangeEnd - 1 )))
lbLast := uint32 (lowbits (uint32 (rangeEnd - 1 )))
answer .highlowcontainer .appendCopiesUntil (bm .highlowcontainer , uint16 (hbStart ))
var max uint32 = maxLowBit
for hb := hbStart ; hb <= hbLast ; hb ++ {
var containerStart uint32
if hb == hbStart {
containerStart = uint32 (lbStart )
}
containerLast := max
if hb == hbLast {
containerLast = uint32 (lbLast )
}
i := bm .highlowcontainer .getIndex (uint16 (hb ))
j := answer .highlowcontainer .getIndex (uint16 (hb ))
if i >= 0 {
c := bm .highlowcontainer .getContainerAtIndex (i ).not (int (containerStart ), int (containerLast )+1 )
if !c .isEmpty () {
answer .highlowcontainer .insertNewKeyValueAt (-j -1 , uint16 (hb ), c )
}
} else {
answer .highlowcontainer .insertNewKeyValueAt (-j -1 , uint16 (hb ),
rangeOfOnes (int (containerStart ), int (containerLast )))
}
}
answer .highlowcontainer .appendCopiesAfter (bm .highlowcontainer , uint16 (hbLast ))
return answer
}
func (rb *Bitmap ) SetCopyOnWrite (val bool ) {
rb .highlowcontainer .copyOnWrite = val
}
func (rb *Bitmap ) GetCopyOnWrite () (val bool ) {
return rb .highlowcontainer .copyOnWrite
}
func (rb *Bitmap ) CloneCopyOnWriteContainers () {
rb .highlowcontainer .cloneCopyOnWriteContainers ()
}
func FlipInt (bm *Bitmap , rangeStart , rangeEnd int ) *Bitmap {
return Flip (bm , uint64 (rangeStart ), uint64 (rangeEnd ))
}
type Statistics struct {
Cardinality uint64
Containers uint64
ArrayContainers uint64
ArrayContainerBytes uint64
ArrayContainerValues uint64
BitmapContainers uint64
BitmapContainerBytes uint64
BitmapContainerValues uint64
RunContainers uint64
RunContainerBytes uint64
RunContainerValues uint64
}
func (rb *Bitmap ) Stats () Statistics {
stats := Statistics {}
stats .Containers = uint64 (len (rb .highlowcontainer .containers ))
for _ , c := range rb .highlowcontainer .containers {
stats .Cardinality += uint64 (c .getCardinality ())
switch c .(type ) {
case *arrayContainer :
stats .ArrayContainers ++
stats .ArrayContainerBytes += uint64 (c .getSizeInBytes ())
stats .ArrayContainerValues += uint64 (c .getCardinality ())
case *bitmapContainer :
stats .BitmapContainers ++
stats .BitmapContainerBytes += uint64 (c .getSizeInBytes ())
stats .BitmapContainerValues += uint64 (c .getCardinality ())
case *runContainer16 :
stats .RunContainers ++
stats .RunContainerBytes += uint64 (c .getSizeInBytes ())
stats .RunContainerValues += uint64 (c .getCardinality ())
}
}
return stats
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .